﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

using RSEngine;

using RSRenderer.Renderer;
using RSRenderer.Device;
using RSRenderer.Imaging;

namespace RS.UI
{
    /// <summary>
    /// This control display the rendering result.
    /// </summary>
    public partial class RenderControl : UserControl, DisplayDevice
    {

        #region Variables

        private RSRenderer.Renderer.Renderer _renderer = new BucketRenderer();

        private WriteableBitmap _bitmap;
        private byte[] _bucketColors;

        #endregion

        #region Constructor

        public RenderControl()
        {
            InitializeComponent();
        }

        #endregion

        #region StartRendering

        public void StartRendering()
        {
            RSRenderer.RenderOptions options = new RSRenderer.RenderOptions();
            options.Groups["BucketRenderer"] = new RSRenderer.Renderer.BucketRenderer_Options();

            // Set the camera
            foreach (IArrangeSupport control in Arranger.Controls)
                if (control is ViewPort3D)
                {
                    ViewPort3D viewport = (ViewPort3D)control;
                    if (viewport.ControlType == ControlType.ViewPort_Perspective)
                    {
                        _renderer.Camera = viewport.Camera.Clone();
                        break;
                    }
                }

            // Initialize the renderer
            _renderer.Initialize(options, Engine.Scene, 600, 600);

            // Start the rendering process
            _renderer.Render(this);
        }

        #endregion

        #region DisplayDevice implementation

        void DisplayDevice.ImageBegin(int width, int height, int bucketSize)
        {
            Dispatcher.Invoke(
                DispatcherPriority.Send,
                new Action(delegate()
                {
                    AsyncImageBegin(width, height);
                })
                );
        }

        private void AsyncImageBegin(int width, int height)
        {
            _bucketColors = new byte[4 * width * height];
            _bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr32, null);
            imgResult.Source = _bitmap;

            //RenderOptions.SetBitmapScalingMode(i, BitmapScalingMode.NearestNeighbor);
            //RenderOptions.SetEdgeMode(i, EdgeMode.Aliased);
        }

        void DisplayDevice.ImagePrepare(int x, int y, int width, int height)
        {
        }

        void DisplayDevice.ImageUpdate(int x, int y, int width, int height, Colour[,] data)
        {
            Dispatcher.BeginInvoke(
                DispatcherPriority.Send,
                new Action(delegate()
                {
                    AsyncImageUpdate(x, y, width, height, data);
                })
                );
        }

        unsafe void AsyncImageUpdate(int x, int y, int width, int height, Colour[,] data)
        {
            int index = 0;
            for (int y0 = 0; y0 < height; y0++)
                for (int x0 = 0; x0 < width; x0++)
                {
                    Colour colour = data[x0, y0];

                    _bucketColors[index + 0] = (byte)(colour.B * 255);
                    _bucketColors[index + 1] = (byte)(colour.G * 255);
                    _bucketColors[index + 2] = (byte)(colour.R * 255);

                    index += 4;
                }

            _bitmap.WritePixels(new Int32Rect(x, y, width, height), _bucketColors, 4 * width, 0);
        }

        void DisplayDevice.ImageFill(int x, int y, int width, int height, Colour colour)
        {
        }

        void DisplayDevice.ImageEnd()
        {
        }

        #endregion

    }
}
